/* link.c is part of VIP program
 * Written by J. Salvador Arias, 2010
 *      CONICET, INSUE, Instituto Miguel Lillo,
 *      Miguel Lillo 205, S.M. de Tucuman (4000)
 *      Tucuman, Argentina
 *      e-mail: jsalarias@csnat.unt.edu.ar
 *
 * VIP is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation and
 * Creative Commons.
 *
 * This file and the VIP program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * To view a copy of this license, visit
 * http://creativecommons.org/licenses/GPL/2.0/
 * or send a letter to
 * Creative Commons, 171 Second Street, Suite 300,
 * San Francisco, California, 94105, USA.
 */

#include "ghead.h"

GList* InsertListElement (GList* prev, gpointer data) {
 GList* nu;

 nu = g_list_append (NULL, data);
 if (prev != NULL) {
   nu -> prev = prev;
   nu -> next = prev -> next;
   if (prev -> next != NULL)
     prev -> next -> prev = nu;
   prev -> next = nu;
 }
 return nu;
}

void PutAtListEnd (GList* dest, GList* toPut) {
 GList* last;

 last = g_list_last (dest);
 toPut -> prev = last;
 if (last != NULL)
   last -> next = toPut;
}

void DestroyList (GList* toDel, gsize sz) {
 GList* nav;
 if (toDel == NULL) return;
 if (g_list_previous (toDel) != NULL)
   g_list_previous (toDel) -> next = NULL;
 for (nav = toDel; nav != NULL; nav = g_list_next (nav))
   g_slice_free1 (sz, nav -> data);
 g_list_free (toDel);
}

void DestroyLinkElement (GList* toDel, gsize sz) {
 if (toDel == NULL) return;
 if (g_list_previous (toDel) != NULL)
   g_list_previous (toDel) -> next = g_list_next (toDel);
 if (g_list_next (toDel) != NULL)
   g_list_next (toDel) -> prev = g_list_previous (toDel);
 toDel -> prev = toDel -> next = NULL;
 g_slice_free1 (sz, toDel -> data);
 g_list_free (toDel);
}

void DestroyLink (GList* toDel) {
 if (toDel == NULL) return;
 if (g_list_previous (toDel) != NULL)
   g_list_previous (toDel) -> next = g_list_next (toDel);
 if (g_list_next (toDel) != NULL)
   g_list_next (toDel) -> prev = g_list_previous (toDel);
 toDel -> prev = toDel -> next = NULL;
 g_list_free (toDel);
}

void AddChildren (GNode* toAdd, GNode* anc, GNode* lastSibling) {
 if (anc == NULL) return;
 toAdd -> parent = anc;
 if (lastSibling == NULL)
   toAdd -> parent -> children = toAdd;
 else
   lastSibling -> next = toAdd;
 toAdd -> prev = lastSibling;
}

GNode* GetNextNode (GNode* actNode) {
 GNode* navNode;

 if (actNode == NULL) return NULL;
 if (g_node_first_child (actNode) != NULL)
   return g_node_first_child (actNode);

 for (navNode = actNode;; navNode = navNode -> parent) {
   if (g_node_next_sibling (navNode) != NULL) return g_node_next_sibling (navNode);
   if (navNode -> parent == NULL) break;
 }
 return navNode;
}

GNode* GetNextTerm (GNode* actNode) {
 GNode* navNode;

 if (actNode == NULL) return NULL;
 navNode = actNode;
 /* Search the next available node, if there are no more nodes, returns NULL */
 if (g_node_first_child (actNode) == NULL) {
   for (; navNode != NULL; navNode = navNode -> parent) {
     if (g_node_next_sibling (navNode) != NULL) {
       navNode = g_node_next_sibling (navNode);
       break;
     }
   }
   if (navNode == NULL) return NULL;
 }
 for (; g_node_first_child (navNode) != NULL; navNode = g_node_first_child (navNode));
 return navNode;
}

GNode* GetPrevNode (GNode* actNode) {
 GNode* navNode;

 if (actNode == NULL) return NULL;
 if (g_node_prev_sibling (actNode) != NULL) return g_node_prev_sibling (actNode);
 if (actNode -> parent != NULL) return actNode -> parent;
 /* actNode is the root, so the "previous" node is the last children of the whole tree */
 for (navNode = actNode; ; navNode = g_node_last_child (navNode))
   if (g_node_last_child (navNode) == NULL) break;
 return navNode;
}

SFLAG IsDesc (GNode* probe, GNode* anc) {
 GNode* navNode;

 if ((probe == NULL) || (anc == NULL)) return FALSE;
 for (navNode = probe; navNode != NULL; navNode = navNode -> parent)
   if (navNode == anc) return TRUE;
 return FALSE;
}

/* Lists of names */

GList* NameOnList (gchar* name, GList* list) {
 GList* nav;
 GList* toRet;
 GString* probe;
 GString* toAdd;
 SINTEGER cmp;

 toRet = list;
 if (list == NULL) {
   toAdd = g_string_new (name);
   toRet = InsertListElement (NULL, toAdd);
   return toRet;
 }
 for (nav = list; nav != NULL; nav = g_list_next (nav)) {
   probe = (GString*) nav -> data;
   cmp = g_strcmp0 (name, probe -> str);
   if (cmp == 0) break;
   else if (cmp < 0) {
     toAdd = g_string_new (name);
     if (nav == list) {
       toRet = InsertListElement (NULL, toAdd);
       toRet -> next = list;
       list -> prev = toRet;
       break;
     }
     InsertListElement (g_list_previous (nav), toAdd);
     break;
   }
   else if (g_list_next (nav) == NULL) {
     toAdd = g_string_new (name);
     InsertListElement (nav, toAdd);
     break;
   }
 }
 return toRet;
}
